package main

import (
	"context"
	"log"
	"os/exec"
	"strconv"
	"time"
)

const (
	typeCheckLogin = iota
	typeFollow
	typeRegister
	typeFenshen
	typeUploadVideo
	typeShua
)

func updateStatus(err error, t Task) {
	if err != nil {
		db.Model(&t).Update("status", TaskFailed)
		return
	}

	db.Model(&t).Update("status", TaskSuccess)
}

func (d *Device) runCommandWithTimeout(c string, timeout time.Duration, arg ...string) error {
	var ctx context.Context
	ctx, d.currentCancel = context.WithTimeout(context.Background(), timeout)
	cmd := exec.CommandContext(ctx, c, arg...)
	cmd.Dir = "../"

	cmd.Start()
	return cmd.Wait()
}

func (d *Device) runStopAll() {
	d.runCommandWithTimeout("python3", 120*time.Second, "stopall.py", d.ID)
}

func (d *Device) runShua(t Task) {
	err := d.runCommandWithTimeout("python3", 120*time.Second, "shua.py", t.DeviceID, t.PName)
	updateStatus(err, t)
}

func (d *Device) runCheckLogin(t Task) {
	err := d.runCommandWithTimeout("python3", 120*time.Second, "check_login.py", t.DeviceID, t.PName)
	updateStatus(err, t)
}

func (d *Device) runFollow(t Task) {
	err := d.runCommandWithTimeout("python3", 5*time.Minute, "follow.py", t.DeviceID, t.PName)
	updateStatus(err, t)
}

func (d *Device) runRegister(t Task) {
	err := d.runCommandWithTimeout("python3", 5*time.Minute, "register.py", t.DeviceID, t.PName)
	updateStatus(err, t)
}

func (d *Device) runFenshen(t Task) {
	err := d.runCommandWithTimeout("python3", 3*time.Minute, "fenshen.py", t.DeviceID, strconv.Itoa(t.ID))
	updateStatus(err, t)
}

func (d *Device) runUpload(t Task) {
	err := d.runCommandWithTimeout("python3", 15*time.Minute, "upload.py", t.DeviceID, t.PName, t.Extra)
	updateStatus(err, t)
}

func (d *Device) runWatch() {
	cmd := exec.Command("python3", "watch.py", d.ID)
	cmd.Dir = "../"
	cmd.Run()
}

func (d *Device) stop() {
	d.cancelCh <- 0
}

func (d *Device) loop() {
	for {
		select {
		case task := <-d.ch:
			db.Model(&task).Update("status", TaskRunning)
			d.CurrentTask = task
			switch task.Type {
			case typeCheckLogin:
				d.runCheckLogin(task)
			case typeFollow:
				d.runFollow(task)
			case typeRegister:
				d.runRegister(task)
			case typeFenshen:
				d.runFenshen(task)
			case typeUploadVideo:
				d.runUpload(task)
			}
		case <-d.cancelCh:
			d.currentCancel()
			close(d.ch)
			goto OUT
		}
	}
OUT:
	log.Println(d.Name, "退出loop")
}

func NewDevice(deviceID string) *Device {
	var d = Device{ID: deviceID}
	notExist := db.Where("id = ?", deviceID).First(&d).RecordNotFound()
	if notExist {
		monitor.initPacks(deviceID)
		d = Device{ID: deviceID, Name: "", Status: OnLine}
		db.Create(&d)
	}
	var packs = make([]Pack, 0, 20)
	db.Model(&d).Related(&packs)
	d.Packs = packs
	d.ch = make(chan Task, 300)
	d.cancelCh = make(chan int)

	monitor.setDevice(&d)
	go d.loop()

	return &d
}
